from dataclasses import dataclass
from hashlib import sha256

from fastapi import status
from fastapi.exceptions import HTTPException
from tortoise.queryset import Q

from app.controllers.base_controller import BaseController
from app.models.account_models import Account
from app.schemas.accounts_schemas import (EditAccountRequestSchema,
                                          GetAccountResponseSchema)
from app.tools.account_tools import AccountTools


@dataclass
class GetAccountByIdController(BaseController):
    """Контроллер получения пользователя по ID"""

    account_id: int

    async def execute(self) -> GetAccountResponseSchema:
        AccountTools.check_account_id_is_valid(self.account_id)

        account = await Account.get_or_none(id=self.account_id)
        if account is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)

        return GetAccountResponseSchema(
            id=account.id,
            firstName=account.firstName,
            lastName=account.lastName,
            email=account.email,
        )


@dataclass
class SearchAccountsController(BaseController):
    """Контроллер поиска пользователя"""

    first_name: str
    last_name: str
    email: str
    from_param: int
    size: int

    async def execute(self):
        accounts = []
        query = Q()

        if self.from_param is not None and self.from_param < 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)
        if self.size is not None and self.size <= 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)
        if self.first_name:
            query &= Q(firstName__icontains=self.first_name)
        if self.last_name:
            query &= Q(lastName__icontains=self.last_name)
        if self.email:
            query &= Q(email__icontains=self.email)

        query = Account.filter(query)

        if self.from_param is not None and self.size is not None:
            query = query.offset(self.from_param).limit(self.size)
        elif self.from_param is not None:
            query = query.offset(self.from_param)
        elif self.size is not None:
            query = query.limit(self.size)

        result = await query

        for account in result:
            accounts.append(
                GetAccountResponseSchema(
                    id=account.id,
                    firstName=account.firstName,
                    lastName=account.lastName,
                    email=account.email,
                )
            )

        return accounts


@dataclass
class EditAccountController(BaseController):
    """Контроллер изменения аккаунта пользователя"""

    account_id: int
    request: EditAccountRequestSchema

    async def execute(self):
        AccountTools.check_account_id_is_valid(self.account_id)
        AccountTools.validate_account_request(request=self.request)
        await AccountTools.check_email_conflict(email=self.request.email)

        account = await Account.get(id=self.account_id)
        account.firstName = self.request.firstName
        account.lastName = self.request.lastName
        account.email = self.request.email
        account.password = sha256(self.request.password.encode("utf-8")).hexdigest()

        await account.save()

        return GetAccountResponseSchema(
            id=account.id,
            firstName=account.firstName,
            lastName=account.lastName,
            email=account.email,
        )


@dataclass
class DeleteAccountController(BaseController):
    """Контроллер для удаления аккаунта"""

    account_id: int

    async def execute(self):
        AccountTools.check_account_id_is_valid(self.account_id)

        account = await Account.get(id=self.account_id)

        await account.delete()
